package br.ufrj.dcc.mapaviolencia.business;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.NoSuchElementException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import twitter4j.JSONObject;
import twitter4j.Paging;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import br.ufrj.dcc.mapaviolencia.exception.URLNotFoundException;
import br.ufrj.dcc.mapaviolencia.model.CategoriasViolencia;
import br.ufrj.dcc.mapaviolencia.model.Noticia;
import br.ufrj.dcc.mapaviolencia.util.DBUtil;
import br.ufrj.dcc.mapaviolencia.util.LocalizacaoUtil;
import br.ufrj.dcc.mapaviolencia.util.TextMiningUtil;
import br.ufrj.dcc.mapaviolencia.util.TwitterUtil;
import br.ufrj.dcc.mapaviolencia.util.URLParserUtil;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;


public class TwitterBusiness {
	
	Logger logger = LoggerFactory.getLogger(TwitterBusiness.class);
	
	public final static String FIELD_ID = "id";
	public final static String FIELD_TIMESTAMP = "timestamp";
	public final static String FIELD_URL = "profileImageURL";
	public final static String FIELD_ = "timestamp";
	public final static String FIELD_CREATE_DATE = "createdAt";

	private static final int FIRST_PAGE = 1;
	private static final int LAST_PAGE = 17;
	
	private Twitter twitter = TwitterFactory.getSingleton();
	
	
	public void searchAndSaveLatestTweets() throws TwitterException {
		searchAndSaveTweets(true);
	}
	
	public void searchAndSaveAllTweets() throws TwitterException {
		searchAndSaveTweets(false);
	}
	
	private void searchAndSaveTweets(boolean untilMostRecently) throws TwitterException {
		Date latestTweetDate = getLatestTweetDate(DBUtil.COLLECTION_TWEETS_G1RIO);
		if (latestTweetDate == null) {
			latestTweetDate = new Date(0l);
		}
		
		int count = 0;
		
		for (int i=FIRST_PAGE; i<=LAST_PAGE; i++) {
			for (Status tweet : twitter.getUserTimeline(TwitterUtil.TWITTER_G1RIO, new Paging(i, 200))) {
				if (untilMostRecently && tweet.getCreatedAt().compareTo(latestTweetDate) <= 0) {
					if (count == 0)logger.info("Nenhum tweet novo encontrado.");
					return;
				}
				String[] palavrasTweet;
				boolean inseriu = false;
				palavrasTweet = tweet.getText().split(" ");

				outerloop:
				for (String palavraDoTweet : palavrasTweet) {	
					for(String palavraViolenta : CategoriasViolencia.TODOSOSTOKENS.tokens){
						if(palavraViolenta.trim().equals(palavraDoTweet.toLowerCase())){
							count++;
							logger.debug(tweet.getText());
							logger.debug(palavraDoTweet.toLowerCase());
							saveTweet(tweet, DBUtil.COLLECTION_TWEETS_G1RIO);
							inseriu = true;
							break outerloop;
						}
					}
					
				}
				//if(!inseriu) logger.info("Tweet não salvo: {}", tweet);
			}
		}
	}

	public void saveTweet(Status tweet, String collectionName) {
		DBCollection collection = DBUtil.getInstance().getDatabase().getCollection(collectionName);
		DBObject dbObject = (DBObject) JSON.parse(new JSONObject(tweet).toString());
		dbObject.put(FIELD_TIMESTAMP, parseDate(dbObject.get(FIELD_CREATE_DATE).toString()).getTime());
		BasicDBObject query = new BasicDBObject(FIELD_ID, dbObject.get(FIELD_ID));
		collection.update(query, dbObject, true, false);
		logger.info("Tweet salvo: {}", tweet);
		saveNoticia(tweet);
	}

	private String getURL(Status status) throws URLNotFoundException {
		try {
			return status.getURLEntities()[0].getExpandedURL().toString();
		} catch (IndexOutOfBoundsException e1) {
			throw new URLNotFoundException();
		} catch (NullPointerException e2) {
			throw new URLNotFoundException();
		}
	}
	
	public void saveNoticia(Status tweet) {
		String url;
		try {
			url = getURL(tweet);
		} catch (URLNotFoundException e) {
			logger.warn("Notícia não salva pois URL não foi encontrada: {}", tweet);
			return;
		}
		
		Noticia noticia = new Noticia();
		noticia.setId(tweet.getId()+"");
		noticia.setUrl(url);
		noticia.setDataHora(tweet.getCreatedAt());
		noticia.setCorpo(URLParserUtil.getPageContent(url));
		noticia.setTitulo(URLParserUtil.getTitulo(url));
		noticia.setSubTitulo(URLParserUtil.getSubTitulo(url));
		String textoTodo = noticia.getCorpo() + " " + noticia.getTitulo() + " " + noticia.getSubTitulo();
		LocalizacaoUtil.findLocalidade(textoTodo,noticia);
		TextMiningUtil.defineCategorias(textoTodo, noticia);
		
		DBCollection collection = DBUtil.getInstance().getDatabase().getCollection(DBUtil.COLLECTION_NOTICIAS);
		DBObject dbObject = (DBObject) JSON.parse(new JSONObject(noticia).toString());
		DBObject query = new BasicDBObject("id", noticia.getId());
		collection.update(query, dbObject, true, false);
		logger.info("Notícia salva: {}", noticia);
	}
	
	public Date getLatestTweetDate(String collectionName) {
		DBCollection collection = DBUtil.getInstance().getDatabase().getCollection(collectionName);
		try {
			DBObject latestTweet = collection.find(new BasicDBObject()).sort(new BasicDBObject(FIELD_TIMESTAMP, -1)).limit(1).next();
			return parseTimestamp(latestTweet.get(FIELD_TIMESTAMP).toString());
		} catch (NoSuchElementException e) {
			return null;
		}
	}
	
	public void removeAllTweets(String collectionName) {
		DBCollection collection = DBUtil.getInstance().getDatabase().getCollection(collectionName);
		collection.remove(new BasicDBObject());
	}

	public static Date parseTimestamp(String date)  {
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(Long.valueOf(date));
		return calendar.getTime();
	}
	
	public static Date parseDate(String date) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
		try {	
			return dateFormat.parse(date);
		} catch (ParseException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static void main(String[] args) throws TwitterException {
		//Carrega estados do banco
		LocalizacaoUtil.initialize();
		TwitterBusiness twitterBusiness = new TwitterBusiness();
		twitterBusiness.searchAndSaveAllTweets();
	}
	
}
